﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;

namespace DGen
{


    public static partial class DText
    {
        /// <summary>
        /// gives count of how many times a characters appears in string. Case sensitive.
        /// </summary>
        /// <param name="stringToSearch"></param>
        /// <param name="charToFind"></param>
        /// <returns></returns>
        public static int CharOccurs(string stringToSearch, char charToFind)
        {
            int count = 0;
            char[] chars = stringToSearch.ToCharArray();
            foreach (char c in chars)
            {
                if (c == charToFind)
                {
                    count++;
                }
            }
            return count;
        }

        
        /// <summary>
        /// Count how many times a substring appears in a string by without Regexp
        /// </summary>
        /// <param name="needle"></param>
        /// <param name="haystack"></param>
        /// <returns></returns>
        public static int CountOccurences(string needle, string haystack)
        {
            if (needle == "\t") { needle = "\\t"; }
            if (needle == @"\t") { needle = "\t"; }
            return (haystack.Length - haystack.Replace(needle, "").Length) / needle.Length;
        }


        #region StringLocators

        /// <summary>
        /// Parses a file system or url path, and locates the file name
        /// </summary>
        /// <param name="fullPath">
        /// String indicating a file system or url path to a file
        /// </param>
        /// <param name="includeFileExtension">
        /// Whether to return file extension in addition to file name
        /// </param>
        /// <returns>
        /// File name, if found, and extension if requested, and located
        /// </returns>
        public static string GetFileNameFromPath(string fullPath,
                                                 bool includeFileExtension)
        {
            try
            {
                bool url = fullPath.Contains(m_ForwardSlash);
                string search = string.Empty;
                if (url)
                    search = m_ForwardSlash;
                else
                    search = m_BackSlash;
                string portion = string.Empty;

                int decimals = GetKeyCharCount(fullPath, m_Period);
                if (decimals >= 1)
                    //get all text to the RIGHT of the LAST slash:
                    portion = GetExactPartOfString(fullPath, search, false,
                                                   false, false);
                else
                    return string.Empty;

                if (includeFileExtension)
                    return portion;
                search = m_Period;
                portion = GetExactPartOfString(portion, search, false,
                                               true, false);
                return portion;
            }
            catch (Exception ex)
            {
                DBug.ErrorTools.ProcessError(ex);
                return null;
            }
        }


        /// <summary>
        /// Parses a url or file stream string, to get and return the 
        /// path portion (sans the file name and extension)
        /// </summary>
        /// <param name="fullPath">
        /// A string indicating a file system path or a url. Can 
        /// contain a file name/extension.
        /// </param>
        /// <returns>
        /// The original path minus the file name and extension, 
        /// if it had existed, with no extension will return
        /// the original string, plus an optional slash
        /// </returns>
        public static string GetFolderPath(string fullPath)
        {
            try
            {
                bool url = fullPath.Contains(m_ForwardSlash);
                string slash = string.Empty;
                if (url)
                    slash = m_ForwardSlash;
                else
                    slash = m_BackSlash;

                string fileName = GetFileNameFromPath(fullPath, true);
                //use tool to return all text to the LEFT of the file name
                string portion = GetStringBetween(fullPath, string.Empty,
                                                  fileName);

                //add the pertinent slash to the end of the string;
                if (portion.Length > 0 && portion.Substring(
                                              portion.Length - 1, 1) != slash)
                    portion += slash;
                return portion;
            }
            catch (Exception ex)
            {
                DBug.ErrorTools.ProcessError(ex);
                return null;
            }
        }


        /// <summary>
        /// Useful to pinpoint exact string between whatever 
        /// characters/string you wish to grab text from
        /// </summary>
        /// <param name="stream">
        /// string from which to cull subtext from
        /// </param>
        /// <param name="from">
        /// string that precedes the text you are looking for
        /// </param>
        /// <param name="to">
        /// string that follows the text you are looking for
        /// </param>
        /// <returns>
        /// The string between point x and point y
        /// </returns>
        public static string GetStringBetween(string stream, string from,
                                              string to)
        {
            try
            {
                string subField = string.Empty;
                subField = RightOf(stream, from);
                subField = LeftOf(subField, to);
                return subField;
            }
            catch (Exception ex)
            {
                DBug.ErrorTools.ProcessError(ex);
                return null;
            }
        }

        /// <summary>
        /// Will return the text to the LEFT of indicated substring 
        /// </summary>
        /// <param name="stream">
        /// string from which to cull a portion of text
        /// </param>
        /// <param name="stringToStopAt">
        /// string that indicates what char or string to stop at
        /// </param>
        /// <returns>
        /// The string to the left of point x (stringToStopAt)
        /// </returns>
        public static string LeftOf (string stream, string stringToStopAt)
        {
            try
            {
                if (stringToStopAt == null || stringToStopAt == string.Empty)
                {
                    return stream;
                }

           
                int findLength = stringToStopAt.Length;


                stringToStopAt = stringToStopAt.ToLower();
                string temp = stream.ToLower();
                int i = temp.IndexOf(stringToStopAt);


                if ((i <= -1) && (stringToStopAt != temp.Substring(0, findLength))
                    || (i == -1))
                    return stream;


                string result = stream.Substring(0, i);
                return result;
            }
            catch (Exception ex)
            {
                DBug.ErrorTools.ProcessError(ex);
                return null;
            }
        }


        /// <summary>
        /// Will return the text to the RIGHT of whatever substring you indicate
        /// </summary>
        /// <param name="stream">
        /// string from which to cull a portion of text
        /// </param>
        /// <param name="stringToStartAfter">
        /// string that indicates what char or string to start after
        /// </param>
        /// <returns>
        /// The string to the right of point x (stringToStartAfter)
        /// </returns>
        public static string RightOf(string stream, string stringToStartAfter)
        {
            try
            {
                if (stringToStartAfter == null || stringToStartAfter == string.Empty)
                    return stream;
                stringToStartAfter = stringToStartAfter.ToLower();
                string temp = stream.ToLower();
                int findLength = stringToStartAfter.Length;
                int i = temp.IndexOf(stringToStartAfter);
                if ((i <= -1) && (stringToStartAfter != temp.Substring(0, findLength))
                    || (i == -1))
                    return stream;

                string result =
                    stream.Substring(i + findLength, stream.Length - (i + findLength));
                return result;
            }
            catch (Exception ex)
            {
                DBug.ErrorTools.ProcessError(ex);
                return null;
            }
        }


        /// <summary>
        /// Searches a string for every single instance of the passed-in
        /// field delimiters, and returns all the values between those
        /// delimiters, as a List object
        /// </summary>
        /// <param name="streamToSearch">string to search</param>
        /// <param name="leftFieldDelimiter">string to start at</param>
        /// <param name="rightFieldDelimiter">string to stop at</param>
        /// <returns>A List object of strings</returns>
        public static List<string> GetEachFieldValue(string streamToSearch,
                                                     string leftFieldDelimiter, string rightFieldDelimiter)
        {
            string search = streamToSearch;
            string field = string.Empty;
            var fields = new List<string>();
            while (!string.IsNullOrEmpty(search)
                   && search.Contains(leftFieldDelimiter)
                   && search.Contains(rightFieldDelimiter))
            {
                //get the val and add to list
                field = GetStringBetween(search, leftFieldDelimiter,
                                         rightFieldDelimiter);
                if (!string.IsNullOrEmpty(field))
                    fields.Add(field);
                //shorten the search string and continue
                search = RightOf(search, field + rightFieldDelimiter);
            }
            return fields;
        }


        /// <summary>
        /// Instructions on using arguments:
        /// Set firstInstance = true, to stop at first instance of locateChar
        /// If firstInstance = false, then the LAST instance of locateChar will be used
        /// Set fromLeft = true, to return string from the left of locateChar
        /// If fromLeft = false, then the string from the right of locateChar 
        /// will be returned.
        /// Set caseSensitive to true/false for case-sensitivity
        /// EXAMPLES:
        /// GetPartOfString('aunt jemima', 'm', 'true', 'true')
        /// will return 'aunt je'
        /// GetPartOfString('aunt jemima', 'm', 'true', 'false')
        /// </summary>
        /// <param name="stream">
        /// The string from which to cull a portion of text
        /// </param>
        /// <param name="locateChar">
        /// The character or string that is the marker
        /// for which to grab text (from left or right depending
        /// on other argument)
        /// </param>
        /// <param name="firstInstance">
        /// Whether or not to get the substring from the first
        /// encountered instance of the locateChar argument
        /// </param>
        /// <param name="fromLeft">
        /// Whether to search from the left. If set to false,
        /// then the string will be searched from the right.
        /// </param>
        /// <param name="caseSensitive">
        /// Whether to consider case (upper/lower)
        /// </param>
        /// <returns>
        /// A portion of the input string, based on ensuing arguments
        /// </returns>
        public static string GetExactPartOfString(string stream, string locateChar,
                                                  bool firstInstance, bool fromLeft, bool caseSensitive)
        {
            try
            {
         
                string tempStream = string.Empty;
                string tempLocateChar = string.Empty;
                if (!caseSensitive)
                {
                    //case doesn't matter, convert to lower:
                    tempStream = stream.ToLower();
                    tempLocateChar = locateChar.ToLower();
                }
                //default charCnt to 1; for first inst of locateChar:
                int charCount = 1;
                if (firstInstance == false)
                    //get number of times char exists in string:
                    if (caseSensitive)
                        charCount = GetKeyCharCount(stream, locateChar);
                    else
                        charCount = GetKeyCharCount(tempStream, tempLocateChar);
                //get position of first/last inst of char in str:
                int position = 0;
                if (caseSensitive)
                    position = GetCharPosition(stream, locateChar, charCount);
                else
                    position = GetCharPosition(tempStream, tempLocateChar, charCount);
                string result = string.Empty;
                //chk that character exists in str:
                if (position == -1)
                    result = string.Empty;
                else
                {
                    //char exists, proceed:
                    int streamLength = stream.Length;
                    if (fromLeft)
                        //return string from left:
                        result = stream.Substring(0, position);
                    else
                    {
                        //return string from right:
                        position += 1;
                        result = stream.Substring(position, streamLength - position);
                    }
                }
                return result;
            }
            catch (Exception ex)
            {
                DBug.ErrorTools.ProcessError(ex);
                return null;
            }
        }

        /// <summary>
        /// Returns the number of times, that the key character is found 
        /// in the stream string
        /// </summary>
        /// <param name="stream">
        /// string in which to locate key character
        /// </param>
        /// <param name="keyChar">
        /// key character: the string or char to count inside the stream
        /// </param>
        /// <returns>
        /// The number of times the string or char was located
        /// </returns>
        public static int GetKeyCharCount(string stream, string keyChar)
        {
            try
            {
                string current;
                int keyCount = 0;
                for (int i = 0; i < stream.Length; i++)
                {
                    current = stream.Substring(i, 1);
                    if (current == keyChar)
                        keyCount += 1;
                }
                if (keyCount <= 0)
                    return -1;
                else
                    return keyCount;
            }
            catch (Exception ex)
            {
                DBug.ErrorTools.ProcessError(ex);
                return -1;
            }
        }


        /// <summary>
        /// Is CASE-SENSITIVE
        /// Returns x position of sChar in sstream, where x = iCharInst. 
        /// If: getCharPos('pineapple', 'p', 3) Then: 6 is returned
        /// </summary>
        /// <param name="stream">
        /// string in which to pinpoint the character (or string) position
        /// </param>
        /// <param name="charToPinpoint">character or string to locate</param>
        /// <param name="whichCharInstance">
        /// Number indicating WHICH instance of the character/string to locate
        /// </param>
        /// <returns>
        /// The index of the character or string found inside the input string.
        /// Will return -1 if the string/character is not found, or if the 
        /// instance number is not found
        /// </returns>
        public static int GetCharPosition(string stream, string charToPinpoint, int whichCharInstance)
        {
            try
            {
                string current;
                int keyCharCount = 0;
                for (int i = 0; i < stream.Length; i++)
                {
                    current = stream.Substring(i, 1);
                    //was BLOCKED SCRIPT sCurr = sstream.charAt(i);
                    if (current == charToPinpoint)
                    {
                        keyCharCount += 1;
                        if (keyCharCount == whichCharInstance)
                            return i;
                    }
                }
                return -1;
            }
            catch (Exception ex)
            {
                DBug.ErrorTools.ProcessError(ex);
                return -1;
            }
        }

        #endregion
    }
}